home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / commands / command.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  14.3 KB  |  552 lines

  1. /* ----------------------------------------------------------------
  2.  *   FILE
  3.  *    command.c
  4.  *    
  5.  *   DESCRIPTION
  6.  *    random postgres portal and utility support code
  7.  *
  8.  *   INTERFACE ROUTINES
  9.  *    PortalCleanup
  10.  *    PerformPortalFetch
  11.  *    PerformPortalClose
  12.  *    PerformAddAttribute
  13.  *
  14.  *   NOTES
  15.  *    The PortalExecutorHeapMemory crap needs to be eliminated
  16.  *    by designing a better executor / portal processing memory
  17.  *    interface.
  18.  *    
  19.  *    The PerformAddAttribute() code, like most of the relation
  20.  *    manipulating code in the commands/ directory, should go
  21.  *    someplace closer to the lib/catalog code.
  22.  *    
  23.  *   IDENTIFICATION
  24.  *    $Header: /private/postgres/src/commands/RCS/command.c,v 1.36 1992/08/25 17:44:00 mer Exp $
  25.  * ----------------------------------------------------------------
  26.  */
  27.  
  28. #include <strings.h>
  29. #include "tmp/postgres.h"
  30.  
  31. RcsId("$Header: /private/postgres/src/commands/RCS/command.c,v 1.36 1992/08/25 17:44:00 mer Exp $");
  32.  
  33. /* ----------------
  34.  *    FILE INCLUDE ORDER GUIDELINES
  35.  *
  36.  *    1) postgres.h
  37.  *    2) various support files ("everything else")
  38.  *    3) node files
  39.  *    4) catalog/ files
  40.  *    5) execdefs.h and execmisc.h, if necessary.
  41.  *    6) extern files come last.
  42.  * ----------------
  43.  */
  44. #include "access/attnum.h"
  45. #include "access/ftup.h"
  46. #include "access/heapam.h"
  47. #include "access/htup.h"
  48. #include "access/relscan.h"
  49. #include "access/skey.h"
  50. #include "access/tqual.h"
  51.  
  52. #include "commands/copy.h"
  53. #include "storage/buf.h"
  54. #include "storage/itemptr.h"
  55. #include "tmp/miscadmin.h"
  56. #include "tmp/portal.h"
  57. #include "utils/excid.h"
  58. #include "utils/log.h"
  59. #include "utils/mcxt.h"
  60. #include "utils/palloc.h"
  61. #include "utils/rel.h"
  62.  
  63. #include "nodes/pg_lisp.h"
  64. #include "nodes/primnodes.h"
  65. #include "tcop/dest.h"
  66. #include "commands/command.h"
  67.  
  68. #include "catalog/catname.h"
  69. #include "catalog/syscache.h"
  70. #include "catalog/pg_attribute.h"
  71. #include "catalog/pg_proc.h"
  72. #include "catalog/pg_relation.h"
  73. #include "catalog/pg_type.h"
  74. #include "catalog/indexing.h"
  75.  
  76. #include "executor/execdefs.h"
  77. #include "executor/execdesc.h"
  78.  
  79. extern List MakeList();
  80.  
  81. /* ----------------
  82.  *     PortalExecutorHeapMemory stuff
  83.  *
  84.  *    This is where the XXXSuperDuperHacky code was. -cim 3/15/90
  85.  * ----------------
  86.  */
  87. MemoryContext PortalExecutorHeapMemory  = NULL;
  88.  
  89. /* --------------------------------
  90.  *     PortalCleanup
  91.  * --------------------------------
  92.  */
  93. void
  94. PortalCleanup(portal)
  95.     Portal    portal;
  96. {
  97.     LispValue    feature;
  98.     MemoryContext    context;
  99.  
  100.     /* ----------------
  101.      *    sanity checks
  102.      * ----------------
  103.      */
  104.     AssertArg(PortalIsValid(portal));
  105.     AssertArg((Pointer)portal->cleanup == (Pointer)PortalCleanup);
  106.  
  107.     /* ----------------
  108.      *    set proper portal-executor context before calling ExecMain.
  109.      * ----------------
  110.      */
  111.     context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
  112.     PortalExecutorHeapMemory = (MemoryContext)
  113.     PortalGetHeapMemory(portal);
  114.  
  115.     /* ----------------
  116.      *    tell the executor to shutdown the query
  117.      * ----------------
  118.      */
  119.     feature = MakeList(lispInteger(EXEC_END), -1);
  120.  
  121.     ExecMain(PortalGetQueryDesc(portal), PortalGetState(portal), feature);
  122.     
  123.     /* ----------------
  124.      *    switch back to previous context
  125.      * ----------------
  126.      */
  127.     (void) MemoryContextSwitchTo(context);
  128.     PortalExecutorHeapMemory = (MemoryContext) NULL;
  129. }
  130.  
  131. /* --------------------------------
  132.  *     PerformPortalFetch
  133.  * --------------------------------
  134.  */
  135. void
  136. PerformPortalFetch(name, forward, count, tag, dest)
  137.     String    name;
  138.     bool    forward;
  139.     Count    count;
  140.     String    tag;
  141.     CommandDest dest;
  142. {
  143.     Portal        portal;
  144.     LispValue        feature;
  145.     List        queryDesc;
  146.     extern List        QueryDescGetTypeInfo();        /* XXX style */
  147.     MemoryContext    context;
  148.  
  149.     /* ----------------
  150.      *    sanity checks
  151.      * ----------------
  152.      */
  153.     if (name == NULL) {
  154.     elog(NOTICE, "PerformPortalFetch: blank portal unsupported");
  155.     return;
  156.     }
  157.     
  158.     /* ----------------
  159.      *    get the portal from the portal name
  160.      * ----------------
  161.      */
  162.     portal = GetPortalByName(name);
  163.     if (! PortalIsValid(portal)) {
  164.     elog(NOTICE, "PerformPortalFetch: %s not found", name);
  165.     return;
  166.     }
  167.     
  168.     /* ----------------
  169.      *     switch into the portal context
  170.      * ----------------
  171.      */
  172.     context = MemoryContextSwitchTo((MemoryContext)PortalGetHeapMemory(portal));
  173.  
  174.     AssertState(context == (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
  175.  
  176.     /* ----------------
  177.      *  setup "feature" to tell the executor what direction and
  178.      *  how many tuples to fetch.
  179.      * ----------------
  180.      */
  181.     if (forward)
  182.     feature = MakeList(lispInteger(EXEC_FOR), lispInteger(count), -1);
  183.     else
  184.     feature = MakeList(lispInteger(EXEC_BACK), lispInteger(count), -1);
  185.  
  186.     /* ----------------
  187.      *    tell the destination to prepare to recieve some tuples
  188.      * ----------------
  189.      */
  190.     queryDesc = PortalGetQueryDesc(portal);
  191.     BeginCommand(name,
  192.          CAtom(GetOperation(queryDesc)),
  193.          QueryDescGetTypeInfo(queryDesc),
  194.          false,    /* portal fetches don't end up in relations */
  195.          false,    /* this is a portal fetch, not a "retrieve portal" */
  196.          tag,
  197.          dest);
  198.  
  199.     /* ----------------
  200.      *    execute the portal fetch operation
  201.      * ----------------
  202.      */
  203.     PortalExecutorHeapMemory = (MemoryContext)
  204.     PortalGetHeapMemory(portal);
  205.     
  206.     ExecMain(queryDesc, PortalGetState(portal), feature);
  207.  
  208.     /* ----------------
  209.      * Note: the "end-of-command" tag is returned by higher-level
  210.      *         utility code
  211.      *
  212.      * Return blank portal for now.
  213.      * Otherwise, this named portal will be cleaned.
  214.      * Note: portals will only be supported within a BEGIN...END
  215.      * block in the near future.  Later, someone will fix it to
  216.      * do what is possible across transaction boundries.
  217.      * ----------------
  218.      */
  219.     (void) MemoryContextSwitchTo((MemoryContext)PortalGetHeapMemory(GetPortalByName(NULL)));
  220. }
  221.  
  222. /* --------------------------------
  223.  *     PerformPortalClose
  224.  * --------------------------------
  225.  */
  226. void
  227. PerformPortalClose(name, dest)
  228.     String    name;
  229.     CommandDest dest;
  230. {
  231.     Portal    portal;
  232.  
  233.     /* ----------------
  234.      *    sanity checks
  235.      * ----------------
  236.      */
  237.     if (name == NULL) {
  238.     elog(NOTICE, "PerformPortalClose: blank portal unsupported");
  239.     return;
  240.     }
  241.  
  242.     /* ----------------
  243.      *    get the portal from the portal name
  244.      * ----------------
  245.      */
  246.     portal = GetPortalByName(name);
  247.     if (! PortalIsValid(portal)) {
  248.     elog(NOTICE, "PerformPortalClose: %s not found", name);
  249.     return;
  250.     }
  251.  
  252.     /* ----------------
  253.      *    Note: PortalCleanup is called as a side-effect
  254.      * ----------------
  255.      */
  256.     PortalDestroy(portal);
  257. }
  258.  
  259. /* --------------------------------
  260.  *     FixDomainList
  261.  * --------------------------------
  262.  */
  263. static List
  264. FixDomainList(domains)
  265.     List    domains;
  266. {
  267.     LispValue    first;
  268.     List        fixedFirst;
  269.     List        result;
  270.     
  271.     if (null(domains))
  272.     return (LispNil);
  273.     
  274.     first = CAR(domains);
  275.     fixedFirst = LispNil;
  276.     
  277.     if (lispStringp(first)) {
  278.     fixedFirst = MakeList(first,
  279.                   lispInteger(-1),
  280.                   lispInteger(strlen(CString(first))),
  281.                   -1);
  282.     } else {
  283.     int len;
  284.     
  285.     len = length(first);
  286.     switch (len) {
  287.     case 1:
  288.         fixedFirst = MakeList(CAR(first),
  289.                   lispInteger(0),
  290.                   lispInteger(-1),
  291.                   -1);
  292.         break;
  293.     case 2:
  294.         fixedFirst = MakeList(CAR(first),
  295.                   CADR(first),
  296.                   lispInteger(-1)
  297.                   -1);
  298.         break;
  299.     case 3:
  300.         fixedFirst = first;
  301.         break;
  302.     default:
  303.         ; /* this cannot happen */
  304.     }
  305.     }
  306.     
  307.     /*
  308.      * return result of processing entire list
  309.      */
  310.     result = FixDomainList(CDR(domains));
  311.     if (! null(fixedFirst)) {
  312.     result = lispCons(fixedFirst, result);
  313.     }
  314.     
  315.     return (result);
  316. }
  317.  
  318. /* ----------------
  319.  *    PerformAddAttribute
  320.  *
  321.  *    adds an additional attribute to a relation
  322.  *
  323.  *    Adds attribute field(s) to a relation.  Each new attribute
  324.  *    is given attnums in sequential order and is added to the
  325.  *    ATTRIBUTE relation.  If the AMI fails, defunct tuples will
  326.  *    remain in the ATTRIBUTE relation for later vacuuming.
  327.  *    Later, there may be some reserved attribute names???
  328.  *
  329.  *    (If needed, can instead use elog to handle exceptions.)
  330.  *
  331.  *    Note:
  332.  *        Initial idea of ordering the tuple attributes so that all
  333.  *    the variable length domains occured last was scratched.  Doing
  334.  *    so would not speed access too much (in general) and would create
  335.  *    many complications in formtuple, amgetattr, and addattribute.
  336.  *
  337.  *    scan attribute catalog for name conflict (within rel)
  338.  *    scan type catalog for absence of data type (if not arg)
  339.  *    create attnum magically???
  340.  *    create attribute tuple
  341.  *    insert attribute in attribute catalog
  342.  *    modify reldesc
  343.  *    create new relation tuple
  344.  *    insert new relation in relation catalog
  345.  *    delete original relation from relation catalog
  346.  * ----------------
  347.  */
  348. void
  349. PerformAddAttribute(relationName, schema)
  350.     Name    relationName;
  351.     List    schema;
  352. {    
  353.     List        element;
  354.     Buffer        buf;
  355.     AttributeNumber    newAttributes;
  356.     
  357.     Relation        relrdesc, attrdesc;
  358.     HeapScanDesc    relsdesc, attsdesc;
  359.     HeapTuple        reltup;
  360.     HeapTuple        attributeTuple;
  361.     AttributeTupleForm    attribute;
  362.     AttributeTupleFormD    attributeD;
  363.     struct attribute    *ap, *attp, **app;
  364.     int            i;
  365.     int            minattnum, maxatts;
  366.     HeapTuple        tup;
  367.     struct    skey    key[2];    /* static better? [?] */
  368.     ItemPointerData    oldTID;
  369.     int            att_nvals;
  370.     Relation        idescs[Num_pg_attr_indices];
  371.     bool        hasindex;
  372.     
  373.     if (issystem(relationName)) {
  374.     elog(WARN, "Add: system relation \"%s\" unchanged",
  375.          relationName);
  376.     return;
  377.     }
  378.  
  379.     /*
  380.      * verify that no attributes are repeated in the list
  381.      */
  382.     foreach (element, schema) {
  383.     List    rest;
  384.     
  385.     foreach (rest, CDR(element)) {
  386.         if (equal((Node)CAR(CAR(element)), (Node)CAR(CAR(rest)))) {
  387.         elog(WARN, "Add: \"%s\" repeated",
  388.              CString(CAR(CAR(element))));
  389.         }
  390.     }
  391.     }
  392.     
  393.     newAttributes = length(schema);
  394.     
  395.     relrdesc = heap_openr(RelationRelationName);
  396.     ScanKeyEntryInitialize((ScanKeyEntry) &key[0],
  397.                    (bits16) NULL,
  398.                    (AttributeNumber) RelationNameAttributeNumber,
  399.                    (RegProcedure) Character16EqualRegProcedure,
  400.                    (Datum)relationName);
  401.     relsdesc = heap_beginscan(relrdesc, 0, NowTimeQual, 1, key);
  402.     reltup = heap_getnext(relsdesc, 0, &buf);
  403.     if (!PointerIsValid(reltup)) {
  404.     heap_endscan(relsdesc);
  405.     heap_close(relrdesc);
  406.     elog(WARN, "addattribute: relation \"%s\" not found",
  407.          relationName);
  408.     return;
  409.     }
  410.     /*
  411.      * XXX is the following check sufficient?
  412.      */
  413.     if (((struct relation *) GETSTRUCT(reltup))->relkind == 'i') {
  414.     elog(WARN, "addattribute: index relation \"%s\" not changed",
  415.          relationName);
  416.     return;
  417.     }
  418.     reltup = palloctup(reltup, buf, relrdesc);
  419.     heap_endscan(relsdesc);
  420.     
  421.     minattnum = ((struct relation *) GETSTRUCT(reltup))->relnatts;
  422.     maxatts = minattnum + newAttributes;
  423.     if (maxatts > MaxHeapAttributeNumber) {
  424.     pfree((char *) reltup);            /* XXX temp */
  425.     heap_close(relrdesc);            /* XXX temp */
  426.     elog(WARN, "addattribute: relations limited to %d attributes",
  427.          MaxHeapAttributeNumber);
  428.     return;
  429.     }
  430.     
  431.     attrdesc = heap_openr(AttributeRelationName);
  432.  
  433.     Assert(attrdesc);
  434.     Assert(RelationGetRelationTupleForm(attrdesc));
  435.  
  436.     /*
  437.      * Open all (if any) pg_attribute indices
  438.      */
  439.     if (hasindex = RelationGetRelationTupleForm(attrdesc)->relhasindex)
  440.     CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
  441.     
  442.     ScanKeyEntryInitialize((ScanKeyEntry)&key[0], 
  443.                (bits16) NULL,
  444.                (AttributeNumber) AttributeRelationIdAttributeNumber,
  445.                (RegProcedure)ObjectIdEqualRegProcedure,
  446.                (Datum) reltup->t_oid);
  447.     
  448.     ScanKeyEntryInitialize((ScanKeyEntry) &key[1],
  449.                (bits16) NULL,
  450.                (AttributeNumber) AttributeNameAttributeNumber,
  451.                            (RegProcedure)Character16EqualRegProcedure,
  452.                (Datum) NULL);
  453.     
  454.     attributeD.attrelid = reltup->t_oid;
  455.     attributeD.attdefrel = InvalidObjectId;    /* XXX temporary */
  456.     attributeD.attnvals = 1;        /* XXX temporary */
  457.     attributeD.atttyparg = InvalidObjectId;    /* XXX temporary */
  458.     attributeD.attbound = 0;        /* XXX temporary */
  459.     attributeD.attcanindex = 0;        /* XXX need this info */
  460.     attributeD.attproc = InvalidObjectId;    /* XXX tempoirary */
  461.     attributeD.attcacheoff = -1;
  462.     
  463.     attributeTuple = addtupleheader(AttributeRelationNumberOfAttributes,
  464.                     sizeof attributeD, (Pointer)&attributeD);
  465.     
  466.     attribute = (AttributeTupleForm)GETSTRUCT(attributeTuple);
  467.     
  468.     i = 1 + minattnum;
  469.     foreach (element, schema) {
  470.     HeapTuple    typeTuple;
  471.     TypeTupleForm    form;
  472.     char *p, *q, r[16];
  473.     int attnelems;
  474.     
  475.     /*
  476.      * XXX use syscache here as an optimization
  477.      */
  478.  
  479.     
  480.  
  481.     key[1].sk_data = (DATUM)CString(CAR(CAR(element)));
  482.     attsdesc = heap_beginscan(attrdesc, 0, NowTimeQual, 2, key);
  483.     tup = heap_getnext(attsdesc, 0, (Buffer *) NULL);
  484.     if (HeapTupleIsValid(tup)) {
  485.         pfree((char *) reltup);        /* XXX temp */
  486.         heap_endscan(attsdesc);        /* XXX temp */
  487.         heap_close(attrdesc);        /* XXX temp */
  488.         heap_close(relrdesc);        /* XXX temp */
  489.         elog(WARN, "addattribute: attribute \"%s\" exists",
  490.          key[1].sk_data);
  491.         return;
  492.     }
  493.     heap_endscan(attsdesc);
  494.     
  495.     /*
  496.      * check to see if it is an array attribute.
  497.      */
  498.  
  499.     p = CString(CAR(CADR(CAR(element))));
  500.  
  501.     if (CDR(CADR(CAR(element))) && IsA(CDR(CADR(CAR(element))),Array))
  502.     {
  503.         Array array;
  504.  
  505.         array = (Array) CDR(CADR(CAR(element)));
  506.         attnelems = get_arrayhigh(array) - get_arraylow(array);
  507.         sprintf(r, "_%s", p);
  508.         p = &r[0];
  509.     }
  510.     else
  511.         attnelems = 1;
  512.  
  513.     typeTuple = SearchSysCacheTuple(TYPNAME,p);
  514.     form = (TypeTupleForm)GETSTRUCT(typeTuple);
  515.     
  516.     if (!HeapTupleIsValid(typeTuple)) {
  517.         elog(WARN, "Add: type \"%s\" nonexistant",
  518.          CString(CADR(CAR(element))));
  519.     }
  520.     /*
  521.      * Note: structure assignment
  522.      */
  523.     attribute->attname = *((Name)key[1].sk_data);
  524.     attribute->atttypid = typeTuple->t_oid;
  525.     attribute->attlen = form->typlen;
  526.     attribute->attnum = i;
  527.     attribute->attbyval = form->typbyval;
  528.     attribute->attnelems = attnelems;
  529.     attribute->attcacheoff = -1;
  530.     
  531.     RelationInsertHeapTuple(attrdesc, attributeTuple,
  532.                 (double *)NULL);
  533.     if (hasindex)
  534.         CatalogIndexInsert(idescs,
  535.                    Num_pg_attr_indices,
  536.                    attrdesc,
  537.                    attributeTuple);
  538.     i += 1;
  539.     }
  540.     
  541.     heap_close(attrdesc);
  542.     ((struct relation *) GETSTRUCT(reltup))->relnatts = maxatts;
  543.     oldTID = reltup->t_ctid;
  544.     heap_replace(relrdesc, &oldTID, reltup);
  545.     pfree((char *) reltup);
  546.     heap_close(relrdesc);
  547.     if (hasindex)
  548.     CatalogCloseIndices(Num_pg_attr_indices, idescs);
  549. }
  550.  
  551.  
  552.